var j = jQuery.noConflict();
(function( j ){

  /**
   * Helper object used to quickly adjust all hidden parent element's, display and visibility properties.
   * This is currently used for the custom drop downs. When the dropdowns are contained within a reveal modal
   * we cannot accurately determine the list-item elements width property, since the modal's display property is set
   * to 'none'.
   *
   * This object will help us work around that problem.
   *
   * NOTE: This could also be plugin.
   *
   * @function hiddenFix
   */
  var hiddenFix = function() {

    return {
      /**
       * Sets all hidden parent elements and self to visibile.
       *
       * @method adjust
       * @param {j Object} jchild
       */

      // We'll use this to temporarily store style properties.
      tmp : [],

      // We'll use this to set hidden parent elements.
      hidden : null,

      adjust : function( jchild ) {
        // Internal reference.
        var _self = this;

        // Set all hidden parent elements, including this element.
        _self.hidden = jchild.parents().andSelf().filter( ":hidden" );

        // Loop through all hidden elements.
        _self.hidden.each( function() {

          // Cache the element.
          var jelem = j( this );

          // Store the style attribute.
          // Undefined if element doesn't have a style attribute.
          _self.tmp.push( jelem.attr( 'style' ) );

          // Set the element's display property to block,
          // but ensure it's visibility is hidden.
          jelem.css( { 'visibility' : 'hidden', 'display' : 'block' } );
        });

      }, // end adjust

      /**
       * Resets the elements previous state.
       *
       * @method reset
       */
      reset : function() {
        // Internal reference.
        var _self = this;
        // Loop through our hidden element collection.
        _self.hidden.each( function( i ) {
          // Cache this element.
          var jelem = j( this ),
              _tmp = _self.tmp[ i ]; // Get the stored 'style' value for this element.

          // If the stored value is undefined.
          if( _tmp === undefined )
            // Remove the style attribute.
            jelem.removeAttr( 'style' );
          else
            // Otherwise, reset the element style attribute.
            jelem.attr( 'style', _tmp );

        });
        // Reset the tmp array.
        _self.tmp = [];
        // Reset the hidden elements variable.
        _self.hidden = null;

      } // end reset

    }; // end return

  };

  j.foundation = j.foundation || {};
  j.foundation.customForms = j.foundation.customForms || {};

  j.foundation.customForms.appendCustomMarkup = function ( options ) {

    var defaults = {
      disable_class: "no-custom"
    };

    options = j.extend( defaults, options );

    function appendCustomMarkup(idx, sel) {
      var jthis = j(sel).hide(),
          type  = jthis.attr('type'),
          jspan = jthis.next('span.custom.' + type);

      if (jspan.length === 0) {
        jspan = j('<span class="custom ' + type + '"></span>').insertAfter(jthis);
      }

      jspan.toggleClass('checked', jthis.is(':checked'));
      jspan.toggleClass('disabled', jthis.is(':disabled'));
    }

    function appendCustomSelect(idx, sel) {
      var hiddenFixObj = hiddenFix();
          //
          // jify the <select> element and cache it.
          //
      var jthis = j( sel ),
          //
          // Find the custom drop down element.
          //
          jcustomSelect = jthis.next( 'div.custom.dropdown' ),
          //
          // Find the custom select element within the custom drop down.
          //
          jcustomList = jcustomSelect.find( 'ul' ),
          //
          // Find the custom a.current element.
          //
          jselectCurrent = jcustomSelect.find( ".current" ),
          //
          // Find the custom a.selector element (the drop-down icon).
          //
          jselector = jcustomSelect.find( ".selector" ),
          //
          // Get the <options> from the <select> element.
          //
          joptions = jthis.find( 'option' ),
          //
          // Filter down the selected options
          //
          jselectedOption = joptions.filter( ':selected' ),
          //
          // Initial max width.
          //
          maxWidth = 0,
          //
          // We'll use this variable to create the <li> elements for our custom select.
          //
          liHtml = '',
          //
          // We'll use this to cache the created <li> elements within our custom select.
          //
          jlistItems
      ;
      var jcurrentSelect = false;
      //
      // Should we not create a custom list?
      //
      if ( jthis.hasClass( options.disable_class ) ) return;

      //
      // Did we not create a custom select element yet?
      //
      if ( jcustomSelect.length === 0 ) {
        //
        // Let's create our custom select element!
        //

            //
            // Determine what select size to use.
            //
        var customSelectSize = jthis.hasClass( 'small' )   ? 'small'   :
                               jthis.hasClass( 'medium' )  ? 'medium'  :
                               jthis.hasClass( 'large' )   ? 'large'   :
                               jthis.hasClass( 'expand' )  ? 'expand'  : ''
        ;
        //
        // Build our custom list.
        //
        jcustomSelect = j('<div class="' + ['custom', 'dropdown', customSelectSize ].join( ' ' ) + '"><a href="#" class="selector"></a><ul /></div>');
        //
        // Grab the selector element
        //
        jselector = jcustomSelect.find( ".selector" );
        //
        // Grab the unordered list element from the custom list.
        //
        jcustomList = jcustomSelect.find( "ul" );
        //
        // Build our <li> elements.
        //
        liHtml = joptions.map( function() { return "<li>" + j( this ).html() + "</li>"; } ).get().join( '' );
        //
        // Append our <li> elements to the custom list (<ul>).
        //
        jcustomList.append( liHtml );
        //
        // Insert the the currently selected list item before all other elements.
        // Then, find the element and assign it to jcurrentSelect.
        //

        jcurrentSelect = jcustomSelect.prepend( '<a href="#" class="current">' + jselectedOption.html() + '</a>' ).find( ".current" );
        //
        // Add the custom select element after the <select> element.
        //
        jthis.after( jcustomSelect )
        //
        //then hide the <select> element.
        //
        .hide();

      } else {
        //
        // Create our list item <li> elements.
        //
        liHtml = joptions.map( function() { return "<li>" + j( this ).html() + "</li>"; } ).get().join( '' );
        //
        // Refresh the ul with options from the select in case the supplied markup doesn't match.
        // Clear what's currently in the <ul> element.
        //
        jcustomList.html( '' )
        //
        // Populate the list item <li> elements.
        //
        .append( liHtml );

      } // endif jcustomSelect.length === 0

      //
      // Determine whether or not the custom select element should be disabled.
      //
      jcustomSelect.toggleClass( 'disabled', jthis.is( ':disabled' ) );
      //
      // Cache our List item elements.
      //
      jlistItems = jcustomList.find( 'li' );

      //
      // Determine which elements to select in our custom list.
      //
      joptions.each( function ( index ) {

        if ( this.selected ) {
          //
          // Add the selected class to the current li element
          //
          jlistItems.eq( index ).addClass( 'selected' );
          //
          // Update the current element with the option value.
          //
          if (jcurrentSelect) {
            jcurrentSelect.html( j( this ).html() );
          }

        }

      });

      //
      // Update the custom <ul> list width property.
      //
      jcustomList.css( 'width', 'auto' );
      //
      // Set the custom select width property.
      //
      jcustomSelect.css( 'width', 'auto' );

      //
      // If we're not specifying a predetermined form size.
      //
      if ( !jcustomSelect.is( '.small, .medium, .large, .expand' ) ) {

        // ------------------------------------------------------------------------------------
        // This is a work-around for when elements are contained within hidden parents.
        // For example, when custom-form elements are inside of a hidden reveal modal.
        //
        // We need to display the current custom list element as well as hidden parent elements
        // in order to properly calculate the list item element's width property.
        // -------------------------------------------------------------------------------------

        //
        // Show the drop down.
        // This should ensure that the list item's width values are properly calculated.
        //
        jcustomSelect.addClass( 'open' );
        //
        // Quickly, display all parent elements.
        // This should help us calcualate the width of the list item's within the drop down.
        //
        hiddenFixObj.adjust( jcustomList );
        //
        // Grab the largest list item width.
        //
        maxWidth = ( jlistItems.outerWidth() > maxWidth ) ? jlistItems.outerWidth() : maxWidth;
        //
        // Okay, now reset the parent elements.
        // This will hide them again.
        //
        hiddenFixObj.reset();
        //
        // Finally, hide the drop down.
        //
        jcustomSelect.removeClass( 'open' );
        //
        // Set the custom list width.
        //
        jcustomSelect.width( maxWidth + 18);
        //
        // Set the custom list element (<ul />) width.
        //
        jcustomList.width(  maxWidth + 16 );

      } // endif

    }

    j('form.custom input:radio[data-customforms!=disabled]').each(appendCustomMarkup);
    j('form.custom input:checkbox[data-customforms!=disabled]').each(appendCustomMarkup);
    j('form.custom select[data-customforms!=disabled]').each(appendCustomSelect);
  };

  var refreshCustomSelect = function(jselect) {
    var maxWidth = 0,
        jcustomSelect = jselect.next();
    joptions = jselect.find('option');
    jcustomSelect.find('ul').html('');

    joptions.each(function () {
      jli = j('<li>' + j(this).html() + '</li>');
      jcustomSelect.find('ul').append(jli);
    });

    // re-populate
    joptions.each(function (index) {
      if (this.selected) {
        jcustomSelect.find('li').eq(index).addClass('selected');
        jcustomSelect.find('.current').html(j(this).html());
      }
    });

    // fix width
    jcustomSelect.removeAttr('style')
      .find('ul').removeAttr('style');
    jcustomSelect.find('li').each(function () {
      jcustomSelect.addClass('open');
      if (j(this).outerWidth() > maxWidth) {
        maxWidth = j(this).outerWidth();
      }
      jcustomSelect.removeClass('open');
    });
    jcustomSelect.css('width', maxWidth + 18 + 'px');
    jcustomSelect.find('ul').css('width', maxWidth + 16 + 'px');

  };

  var toggleCheckbox = function(jelement) {
    var jinput = jelement.prev(),
        input = jinput[0];

    if (false === jinput.is(':disabled')) {
        input.checked = ((input.checked) ? false : true);
        jelement.toggleClass('checked');

        jinput.trigger('change');
    }
  };

  var toggleRadio = function(jelement) {
    var jinput = jelement.prev(),
        jform = jinput.closest('form.custom'),
        input = jinput[0];

    if (false === jinput.is(':disabled')) {
      jform.find('input:radio[name="' + jinput.attr('name') + '"]').next().not(jelement).removeClass('checked');
      if ( !jelement.hasClass('checked') ) {
        jelement.toggleClass('checked');
      }
      input.checked = jelement.hasClass('checked');

      jinput.trigger('change');
    }
  };

  j(document).on('click', 'form.custom span.custom.checkbox', function (event) {
    event.preventDefault();
    event.stopPropagation();

    toggleCheckbox(j(this));
  });

  j(document).on('click', 'form.custom span.custom.radio', function (event) {
    event.preventDefault();
    event.stopPropagation();

    toggleRadio(j(this));
  });

  j(document).on('change', 'form.custom select[data-customforms!=disabled]', function (event) {
    refreshCustomSelect(j(this));
  });

  j(document).on('click', 'form.custom label', function (event) {
    var jassociatedElement = j('#' + j(this).attr('for') + '[data-customforms!=disabled]'),
        jcustomCheckbox,
        jcustomRadio;
    if (jassociatedElement.length !== 0) {
      if (jassociatedElement.attr('type') === 'checkbox') {
        event.preventDefault();
        jcustomCheckbox = j(this).find('span.custom.checkbox');
        //the checkbox might be outside after the label
        if (jcustomCheckbox.length == 0) {
            jcustomCheckbox = j(this).next('span.custom.checkbox');
        }
        //the checkbox might be outside before the label
        if (jcustomCheckbox.length == 0) {
            jcustomCheckbox = j(this).prev('span.custom.checkbox');
        }
        toggleCheckbox(jcustomCheckbox);
      } else if (jassociatedElement.attr('type') === 'radio') {
        event.preventDefault();
        jcustomRadio = j(this).find('span.custom.radio');
        //the radio might be outside after the label
        if (jcustomRadio.length == 0) {
            jcustomRadio = j(this).next('span.custom.radio');
        }
        //the radio might be outside before the label
        if (jcustomRadio.length == 0) {
            jcustomRadio = j(this).prev('span.custom.radio');
        }
        toggleRadio(jcustomRadio);
      }
    }
  });

  j(document).on('click', 'form.custom div.custom.dropdown a.current, form.custom div.custom.dropdown a.selector', function (event) {
    var jthis = j(this),
        jdropdown = jthis.closest('div.custom.dropdown'),
        jselect = jdropdown.prev();

    event.preventDefault();
    j('div.dropdown').removeClass('open');

    if (false === jselect.is(':disabled')) {
        jdropdown.toggleClass('open');

        if (jdropdown.hasClass('open')) {
          j(document).bind('click.customdropdown', function (event) {
            jdropdown.removeClass('open');
            j(document).unbind('.customdropdown');
          });
        } else {
          j(document).unbind('.customdropdown');
        }
        return false;
    }
  });

  j(document).on('click', 'form.custom div.custom.dropdown li', function (event) {
    var jthis = j(this),
        jcustomDropdown = jthis.closest('div.custom.dropdown'),
        jselect = jcustomDropdown.prev(),
        selectedIndex = 0;

    event.preventDefault();
    event.stopPropagation();
    j('div.dropdown').removeClass('open');

    jthis
      .closest('ul')
      .find('li')
      .removeClass('selected');
    jthis.addClass('selected');

    jcustomDropdown
      .removeClass('open')
      .find('a.current')
      .html(jthis.html());

    jthis.closest('ul').find('li').each(function (index) {
      if (jthis[0] == this) {
        selectedIndex = index;
      }

    });
    jselect[0].selectedIndex = selectedIndex;

    jselect.trigger('change');
  });


  j.fn.foundationCustomForms = j.foundation.customForms.appendCustomMarkup;

})( j );
